/*
 * Copyright 2011-2012 by The Regents of the University of California Licensed
 * under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. you may obtain a copy of the
 * License from
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package edu.ucsd.db.bassarisk.schema;

import edu.ucsd.db.bassarisk.query.Constants;
import edu.ucsd.db.bassarisk.schema.Schema.Cardinality;
import edu.ucsd.db.bassarisk.schema.visitor.SchemaNodeVisitor;

public abstract class SchemaNode {
  public static final SchemaRunNode POSITON_SPACE =
      new SchemaRunNode(Constants.PositionSpaceFlag, Cardinality.Star);
  private final Cardinality cardinality;
  private final String name;
  private SchemaNode parent;
  private int postorderNumber;
  private int preorderNumber;

  protected SchemaNode(final String tag, final Cardinality cardinality) {
    this.name = tag;
    this.cardinality = cardinality;
  }

  public abstract <R, A> R accept(SchemaNodeVisitor<R, A> visitor, A arg);

  public boolean contains(final SchemaNode other) {
    return this.preorderNumber < other.preorderNumber
        && this.postorderNumber > other.postorderNumber;
  }

  public boolean excludes(final SchemaNode other) {
    SchemaNode thisAncestor = this;
    SchemaNode otherAncestor = other;
    while (thisAncestor.preorderNumber != otherAncestor.preorderNumber) {
      if (thisAncestor.preorderNumber > otherAncestor.preorderNumber) {
        thisAncestor = thisAncestor.parent;
      } else {
        otherAncestor = otherAncestor.parent;
      }
    }
    return thisAncestor instanceof DisjointChildrenNode;
  }

  public Cardinality getCardinality() {
    return this.cardinality;
  }

  public String getName() {
    return this.name;
  }

  public SchemaNode getParent() {
    return this.parent;
  }

  public SchemaNode getParentRun() {
    SchemaNode parent = this.parent;
    while(parent instanceof DisjointChildrenNode) {
      parent = parent.parent;
    }
    return parent;
  }

  public void setParent(final SchemaNode parent) {
    this.parent = parent;
  }

  public void setPostorder(final int number) {
    this.postorderNumber = number;
  }

  public void setPreorder(final int number) {
    this.preorderNumber = number;
  }
}
